package com.castle.fortress.admin.job.task;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.castle.fortress.admin.oa.dto.AttendanceSettingDto;
import com.castle.fortress.admin.oa.entity.AttendanceRecordEntity;
import com.castle.fortress.admin.oa.entity.DateHolidayEntity;
import com.castle.fortress.admin.oa.entity.DayStatisticsEntity;
import com.castle.fortress.admin.oa.enums.AttendanceRecordStatusEnum;
import com.castle.fortress.admin.oa.enums.AttendanceRecordTypeEnum;
import com.castle.fortress.admin.oa.enums.AttendanceTypeEnum;
import com.castle.fortress.admin.oa.service.AttendanceRecordService;
import com.castle.fortress.admin.oa.service.AttendanceSettingService;
import com.castle.fortress.admin.oa.service.DateHolidayService;
import com.castle.fortress.admin.oa.service.DayStatisticsService;
import com.castle.fortress.admin.system.entity.SysUser;
import com.castle.fortress.admin.system.service.SysUserService;
import com.castle.fortress.admin.utils.RedisUtils;
import com.castle.fortress.common.enums.YesNoEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 打卡记录状态 用来判断是否打卡 白名单用户需要正常生成
 **/
@Component("attendanceRecordTask")
public class AttendanceRecordTask implements ITask {
    @Autowired
    private AttendanceRecordService recordService;
    @Autowired
    private AttendanceSettingService settingService;

    @Autowired
    private DayStatisticsService dayStatisticsService;

    @Autowired
    private SysUserService userService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private DateHolidayService dateHolidayService;

    private static final int saveLimit = 30;

    @Transactional
    @Override
    public void runTask(String params) {
        System.out.println("执行attendanceRecordTask开始");
        List<AttendanceRecordEntity> amEntities = new ArrayList<>();
        List<AttendanceRecordEntity> pmEntities = new ArrayList<>();
        String now = DateUtil.now();
        if (params != null && !"".equals(params)) {
            now = DateUtil.parse(params).toString();
        }
        this.checkIsHolidays(now);
        DateTime dateTime = DateUtil.parseDateTime(now);
        Date begin = DateUtil.beginOfDay(dateTime.toJdkDate());
        Date end = DateUtil.endOfDay(dateTime.toJdkDate());
        //根据 用户表关联今日打卡记录获取今日未打上班卡

        this.amHandle(DateUtil.parse(now), begin, end, amEntities);
        //根据 用户表关联今日打卡记录获取今日未打下班卡
        this.pmHandle(DateUtil.parse(now), begin, end, pmEntities);


        if (amEntities.size() > saveLimit) {
            List<List<AttendanceRecordEntity>> split = ListUtil.split(amEntities, saveLimit);
            split.forEach(item -> {
                recordService.saveBatch(item);
            });
        } else {
            recordService.saveBatch(amEntities);
        }
        if (pmEntities.size() > saveLimit) {
            List<List<AttendanceRecordEntity>> split = ListUtil.split(pmEntities, saveLimit);
            split.forEach(item -> {
                recordService.saveBatch(item);
            });
        } else {
            recordService.saveBatch(pmEntities);
        }
        this.dayStatistics(now);
        System.out.println("执行attendanceRecordTask结束");
    }

    private void checkIsHolidays(String nowDate) {
        boolean result = false;
        final String dateStr = DateUtil.parse(nowDate).toDateStr();
        final QueryWrapper<DateHolidayEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("date", dateStr);
        final DateHolidayEntity one = dateHolidayService.getOne(queryWrapper);
        if (one != null && "3".equals(one.getType().toString())) {
            result = true;
        }
        redisUtils.set("toDayIsHolidays", result);
    }

    private Boolean isLegalHolidays() {
        return (Boolean) redisUtils.get("toDayIsHolidays");
    }

    private void dayStatistics(String now) {
        //查询今天已存在的假期统计的用户 然后不处理这些人
        final String nowDate = DateUtil.format(DateUtil.parse(now), DatePattern.NORM_DATE_FORMAT);
        ArrayList<Long> userIds = dayStatisticsService.getExistsIds(nowDate);
        //获取今天的异常打卡记录 然后写入统计表
        ArrayList<Long> errorUserId = new ArrayList<>();
        QueryWrapper<AttendanceRecordEntity> errorQueryWrapper = new QueryWrapper<>();
        errorQueryWrapper.select("DISTINCT user_id,dept_id,sett_id,date,status");
        errorQueryWrapper.eq("date", nowDate);
        errorQueryWrapper.notIn("status", 0, 5, 6, 7);
        if (userIds.size() > 0) {
            errorQueryWrapper.notIn("user_id", userIds);
        }
        List<DayStatisticsEntity> statisticsEntities = new ArrayList<>();
        List<AttendanceRecordEntity> errorList = recordService.list(errorQueryWrapper);
        errorList.forEach(item -> {
            final DayStatisticsEntity dayStatisticsEntity = new DayStatisticsEntity();
            dayStatisticsEntity.setDate(item.getDate());
            dayStatisticsEntity.setStatus(YesNoEnum.NO.getCode());
            dayStatisticsEntity.setUserId(item.getUserId());
            dayStatisticsEntity.setDeptId(item.getDeptId());
            dayStatisticsEntity.setSettId(item.getSettId());
            statisticsEntities.add(dayStatisticsEntity);
            errorUserId.add(item.getUserId());
        });
//        获取所有正常的记录
        QueryWrapper<AttendanceRecordEntity> normalQueryWrapper = new QueryWrapper<>();
        normalQueryWrapper.select("DISTINCT user_id,dept_id,sett_id,date,status");
        normalQueryWrapper.eq("date", nowDate);
        normalQueryWrapper.in("status", 0, 5, 6, 7);
        if (errorUserId.size() > 0) {
            normalQueryWrapper.notIn("user_id", errorUserId);
        }
        if (userIds.size() > 0) {
            errorQueryWrapper.notIn("user_id", userIds);
        }
        List<AttendanceRecordEntity> normalList = recordService.list(normalQueryWrapper);
        normalList.forEach(item -> {
            final DayStatisticsEntity dayStatisticsEntity = new DayStatisticsEntity();
            dayStatisticsEntity.setDate(item.getDate());
            dayStatisticsEntity.setStatus(item.getStatus());//0正常打卡 5 白名单 6非工作日 7法定节假日 9请假
            dayStatisticsEntity.setUserId(item.getUserId());
            dayStatisticsEntity.setDeptId(item.getDeptId());
            dayStatisticsEntity.setSettId(item.getSettId());
            statisticsEntities.add(dayStatisticsEntity);
        });
        if (statisticsEntities.size() > saveLimit) {
            List<List<DayStatisticsEntity>> split = ListUtil.split(statisticsEntities, saveLimit);
            split.forEach(item -> {
                dayStatisticsService.saveBatch(item);
            });
        } else {
            dayStatisticsService.saveBatch(statisticsEntities);
        }
    }

    private void amHandle(Date now, Date begin, Date end, List<AttendanceRecordEntity> amEntities) {
        List<SysUser> nonAmUser = userService.noPunched(AttendanceRecordTypeEnum.AM.getCode(), begin, end);
        nonAmUser.forEach(item -> {
            System.out.println("user:");
            System.out.println(item);
            //判断此用户是否存在其设置白名单 不存在直接写入未打卡
            AttendanceSettingDto setting = settingService.currentUserSetting(item, AttendanceTypeEnum.COMMUTE.getCode());
            if (setting == null) {
                System.out.println("无法获取对应设置");
                return;
            }
            if (setting.getAttendanceSettingDateEntity() == null) {
                System.out.println("无法获取对应时间设置");
                return;
            }
            AttendanceRecordEntity temp = new AttendanceRecordEntity();
            temp.setType(AttendanceRecordTypeEnum.AM.getCode());
            temp.setSettId(setting.getId());
            temp.setUserId(item.getId());
            temp.setAttendanceTime(setting.getAttendanceSettingDateEntity().getStartTime());
            temp.setDeptId(item.getDeptId());//部门id
            temp.setDate(DateUtil.format(now, DatePattern.NORM_DATE_FORMAT));
            temp.setGmtTime(setting.getAttendanceSettingDateEntity().getAmStartTime() + "~" + setting.getAttendanceSettingDateEntity().getAmEndTime());
            temp.setStatus(AttendanceRecordStatusEnum.NOT_PUNCHED.getCode());
            if (setting.getWhite() != null && !"".equals(setting.getWhite())) {
                List<String> white = Arrays.asList(setting.getWhite().split(","));
                if (white.contains(item.getId().toString())) {
                    //写入到白名单记录
                    temp.setStatus(AttendanceRecordStatusEnum.WHITE_LIST.getCode());
                }
            }
            boolean isWorkDay = setting.getAttendanceSettingDateEntity().getWorkDay().contains(now.getDay() + "");
            //如果不是工作日 那就写入工作日记录
            if (!isWorkDay) {
                temp.setStatus(AttendanceRecordStatusEnum.NO_WORK_DAY.getCode());
            }
            //法定节假日
            if (this.isLegalHolidays()) {
                temp.setStatus(AttendanceRecordStatusEnum.LEGAL_HOLIDAYS.getCode());
            }
            //获取今天星期几
            amEntities.add(temp);
        });
    }

    private void pmHandle(Date now, Date begin, Date end, List<AttendanceRecordEntity> pmEntities) {
        List<SysUser> nonPmUser = userService.noPunched(AttendanceRecordTypeEnum.PM.getCode(), begin, end);
        nonPmUser.forEach(item -> {
            //判断此用户是否存在其设置白名单 不存在直接写入未打卡
            AttendanceSettingDto setting = settingService.currentUserSetting(item, AttendanceTypeEnum.COMMUTE.getCode());
            if (setting == null) {
                System.out.println("无法获取对应设置");
                return;
            }
            if (setting.getAttendanceSettingDateEntity() == null) {
                System.out.println("无法获取对应时间设置");
                return;
            }
            AttendanceRecordEntity temp = new AttendanceRecordEntity();
            temp.setType(AttendanceRecordTypeEnum.PM.getCode());
            temp.setSettId(setting.getId());
            temp.setUserId(item.getId());
            temp.setAttendanceTime(setting.getAttendanceSettingDateEntity().getEndTime());
            temp.setDeptId(item.getDeptId());//部门id
            temp.setDate(DateUtil.format(now, DatePattern.NORM_DATE_FORMAT));
            temp.setGmtTime(setting.getAttendanceSettingDateEntity().getPmStartTime() + "~" + setting.getAttendanceSettingDateEntity().getPmEndTime());
            temp.setStatus(AttendanceRecordStatusEnum.NOT_PUNCHED.getCode());
            if (setting.getWhite() != null && !"".equals(setting.getWhite())) {
                List<String> white = Arrays.asList(setting.getWhite().split(","));
                if (white.contains(item.getId().toString())) {
                    //写入到白名单记录
                    temp.setStatus(AttendanceRecordStatusEnum.WHITE_LIST.getCode());
                }
            }
            boolean isWorkDay = setting.getAttendanceSettingDateEntity().getWorkDay().contains(now.getDay() + "");
            if (!isWorkDay) {
                //如果不是工作日 那就写入工作日记录
                temp.setStatus(AttendanceRecordStatusEnum.NO_WORK_DAY.getCode());
            }
            //法定节假日
            if (this.isLegalHolidays()) {
                temp.setStatus(AttendanceRecordStatusEnum.LEGAL_HOLIDAYS.getCode());
            }
            pmEntities.add(temp);
        });
    }


}
